package org.oslo.mule.service;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.oslo.domain.HotelInfo;
import org.oslo.domain.SearchInfo;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class KayakService {
	
	//CONSTANTS
	String hostname = "http://www.kayak.com";
	String token = "mCHpMz2L_a_OrEkz3FSiDg";
	String sessionid, searchid;
	char searchtype;
	int lastcount;
	List<HotelInfo> hotelList = new ArrayList<HotelInfo>();
	
	public List<HotelInfo> doHotelSearch(SearchInfo searchInfo) {
		sessionid = getSession();
		System.out.println("Session ID:\t" + sessionid );
		
		String toSearchFor = searchInfo.getConferenceLocation().substring(searchInfo.getConferenceLocation().indexOf(',') + 1);
		System.out.println(toSearchFor);
		searchid = searchHotels(toSearchFor, "2007-09-11", "2007-09-13");
		System.out.println("Search ID:\t"+ searchid);
		while (pollResults()) {
			System.out.println("waiting for more...");
		}
		return hotelList;
	}
	
	private String getSession(){
		System.out.println("Token:\t\t" + token  );
		String response = fetch(hostname+"/k/ident/apisession?token=" + token);
		Element root = getDocumentElement(response);
		NodeList sessionid = root.getElementsByTagName("sid");
		if( sessionid.getLength() == 0){
			System.out.println("BAD TOKEN: " + response);
			//System.exit(1);
		}
		return sessionid.item(0).getFirstChild().getNodeValue();
	}
	
	private String searchHotels(String cityandcountry, String checkindate, String checkoutdate) {
		try {
			cityandcountry = URLEncoder.encode(cityandcountry,"UTF-8");  
			checkindate = URLEncoder.encode(checkindate,"UTF-8");
			checkoutdate = URLEncoder.encode(checkoutdate, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		String url= hostname +"/s/apisearch?basicmode=true&othercity=" +cityandcountry +
		"&checkin_date=" + checkindate + "&checkout_date="+ checkoutdate +"&minstars=-1&guests1=1&guests2=1&rooms=1&action=dohotels&apimode=1"+
		"&_sid_=" + sessionid;
		return startSearch(url);
		
	}
	
	private String startSearch(String uri){
		String response = fetch(uri);
		Element root = getDocumentElement(response);
		NodeList searchid = root.getElementsByTagName("searchid");
		if( searchid.getLength() == 0) {
			System.out.println("SEARCH ERROR: \n" + response);
			//System.exit(1);
		}
		return searchid.item(0).getFirstChild().getNodeValue();
	}

	private boolean pollResults(){
		String uri = hostname+ "/s/apibasic/hotel?searchid="+searchid+ "&apimode=1&_sid_=" + sessionid; 
		String response = fetch(uri);
		return handleResults(response);
	}
	
	private boolean handleResults(String response){
		boolean more = false;
		Document root = getDocument(response);
		
		lastcount = Integer.parseInt( root.getElementsByTagName("count").item(0).
				getFirstChild().getNodeValue());
		
		if (root.getElementsByTagName("morepending").getLength() != 0) {
			NodeList pendingList = root.getElementsByTagName("morepending");
			if(pendingList != null) {
				Node pendingNode = pendingList.item(0);
				if(pendingNode != null) {
					Node pendingText = pendingNode.getFirstChild();
					if(pendingText != null) {
						more = pendingText.getNodeValue().equals("true");
					}
				}
			}
		}
		NodeList hotel = root.getElementsByTagName("hotel");
		for(int count = 0; count < hotel.getLength(); count++) {
			HotelInfo hotelInfo = new HotelInfo();
			NodeList childnodes = hotel.item(count).getChildNodes();
			for(int countchild = 0; countchild < childnodes.getLength(); countchild++){
				String nodename = childnodes.item(countchild).getNodeName();
				Node childnode = childnodes.item(countchild);
				if (nodename.equals("stars"))
					hotelInfo.setNumberOfStars(Float.parseFloat(childnode.getFirstChild().getNodeValue()));
				else if (nodename.equals("name"))
					hotelInfo.setName(childnode.getFirstChild().getNodeValue());
				else if (nodename.equals("pricehistorylo"))
					hotelInfo.setPriceLow(Float.parseFloat(childnode.getFirstChild().getNodeValue()));
				else if (nodename.equals("pricehistoryhi"))
					hotelInfo.setPriceHigh(Float.parseFloat(childnode.getFirstChild().getNodeValue()));
				else if (nodename.equals("lat"))
					hotelInfo.setLatitude(Double.parseDouble(childnode.getFirstChild().getNodeValue()));
				else if (nodename.equals("lon"))
					hotelInfo.setLongitude(Double.parseDouble(childnode.getFirstChild().getNodeValue()));	
				else if (nodename.equals("address"))
					hotelInfo.setAddress(childnode.getFirstChild().getNodeValue());
				else if (nodename.equals("city"))
					hotelInfo.setCity(childnode.getFirstChild().getNodeValue());		
			}
			hotelList.add(hotelInfo);
		}
		return more;
	}
	
	private Element getDocumentElement(String response){
		Document doc = null;
		try {
		     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		     DocumentBuilder db = dbf.newDocumentBuilder();
		     ByteArrayInputStream bais = new ByteArrayInputStream(response.getBytes());
		     doc = db.parse(bais);
		} catch (Exception e) {
			e.printStackTrace();
		}
		    
		return doc.getDocumentElement();
		
	}
	
	private Document getDocument(String response){
		Document doc = null;
		try {
		    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		    DocumentBuilder db = dbf.newDocumentBuilder();
		    ByteArrayInputStream bais = new ByteArrayInputStream(response.getBytes());
		    doc = db.parse(bais);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return doc;
	}
	
	
	private String fetch(String urlstring){
		String content = "";
		try {
			/*Properties props = System.getProperties();
			props.put("http.proxyHost", "www-proxy1.nl.int.atosorigin.com");
			props.put("http.proxyPort", "8080");*/
			URL url  = new URL(urlstring);
	        InputStream is = url.openStream();
	        BufferedReader d = new BufferedReader(new InputStreamReader(is));
	        String s;
	        while (null != (s = d.readLine())) {
	            content = content + s + "\n";
	        }
	        is.close();
		} catch ( Exception e ) { 
			e.printStackTrace(); 
		}
		return content;
	}
}
